package com.aispeech.asr.apis.ssc.beans;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.aispeech.asr.apis.ssc.config.AppConfig;
import com.aispeech.asr.apis.ssc.constants.Progress;
import com.aispeech.asr.apis.ssc.data.domain.Align;
import com.aispeech.asr.apis.ssc.data.domain.AudioInfo;
import com.aispeech.asr.apis.ssc.data.domain.PrepareAudioInfo;
import com.aispeech.asr.apis.ssc.data.domain.TaskDoc;
import com.aispeech.asr.apis.ssc.data.domain.VprAudioInfo;
import com.aispeech.asr.apis.ssc.event.SscEvent;
import com.aispeech.asr.apis.ssc.service.ProgressManager;
import com.aispeech.asr.comm.enums.ErrorCode;
import com.aispeech.asr.comm.exceptions.AsrException;
import com.aispeech.asr.comm.utils.FileUtils;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;


@Slf4j
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AudioPrepare implements Function<SscEvent, SscEvent> {

    @Autowired
    AppConfig config;
    @Autowired
    ProgressManager progressManager;

    @SneakyThrows
    @Override
    public SscEvent apply(SscEvent event) {
        TaskDoc taskDoc = event.getTaskDoc();
        log.info("[ AudioPrepare ] start。。。taskId:{}",taskDoc.getId());
        if (taskDoc.getProgress() >= Progress.AUDIOPREPARED) {
            return event;
        }

        progressManager.syncToMongo(taskDoc, Progress.AUDIOPREPAREING);
        taskDoc.addMetric("audioprepareing_t");

        processAudio(event);
        
        log.info("[ AudioPrepare ] end。。。taskId:{}",taskDoc.getId());
        return event;
    }

    private void processAudio(SscEvent event) throws AsrException, IOException {
        AudioInfo audioInfo = event.getAudioInfo();
        TaskDoc taskDoc = event.getTaskDoc();
        List<Align> aligns = taskDoc.getAligns();
        
        //FileUtils.deleteDirectory(new File(audioInfo.getWorkDir()+"/wav"));//重新做的话需要先删除
        
        // 根据aligns信息，为每个uid准备一个超过1分钟的音频
        ByteArrayInputStream audioInputStream = null; 
        try {
        	File audio = new File(audioInfo.getOrignAudio());
            byte[] audioByte= org.apache.commons.io.FileUtils.readFileToByteArray(audio);
            audioInputStream = new ByteArrayInputStream(audioByte);
            log.info("====processAudio==taskId:{},audioInputStream:{}",taskDoc.getId(),audioInputStream.available());
            Map<String,PrepareAudioInfo> prepareAudioInfoMap = new HashMap<String,PrepareAudioInfo>();
            if(aligns != null && aligns.size()>0) {
            	PrepareAudioInfo prepareAudioInfo;
            	for(Align align: aligns) {
            		String uid = String.valueOf(align.getUid());
            		
            		long startOffset = AppConfig.pcmMsecsToBytes(align.getStart(),audioInfo.getSampleRate(),audioInfo.getChannel(),audioInfo.getSampleBytes());
            		long endOffset = AppConfig.pcmMsecsToBytes(align.getEnd(),audioInfo.getSampleRate(),audioInfo.getChannel(),audioInfo.getSampleBytes());
            		int length = (int) (endOffset-startOffset);
            		//log.info("====processAudio==taskId:{},align.getStart():{},align.getEnd():{},startOffset:{},endOffset:{},length:{}",taskDoc.getId(),align.getStart(),align.getEnd(),startOffset,endOffset,length);
            		if(prepareAudioInfoMap.containsKey(uid)) {
            			prepareAudioInfo = prepareAudioInfoMap.get(uid);
            			//计算ms，小于1分钟的时候添加进去
            			if(!prepareAudioInfo.isLimitFlag()) {
            				long duration =  AppConfig.pcmBytesToMsecs(prepareAudioInfo.bufferLength(), audioInfo.getSampleRate(), audioInfo.getChannel(), audioInfo.getSampleBytes());
                			if(duration < 60*1000) {
                				//log.info("====duration==taskId:{},startOffset:{},endOffset:{},length:{}",taskDoc.getId(),startOffset,endOffset,length);
                				byte[] readBytes = new byte[length];
                				audioInputStream.skip(startOffset);
                    			audioInputStream.read(readBytes, 0, length);
                    			prepareAudioInfo.write(readBytes);
                			}else {
                				prepareAudioInfo.setLimitFlag(true);
                			}
            			}
            		}else {
            			String auidoPath = String.format("%s/prepare/%s.%s", audioInfo.getWorkDir(),uid,audioInfo.getAudioType().key());
            			prepareAudioInfo = new PrepareAudioInfo(uid,auidoPath);
            			
            			byte[] readBytes = new byte[length];
            			audioInputStream.skip(startOffset);
            			audioInputStream.read(readBytes,  0, length);
            			prepareAudioInfo.write(readBytes);
            			prepareAudioInfoMap.put(uid, prepareAudioInfo);
            		}
            		audioInputStream.reset();
            	}
            }
            
            audioInputStream.close();
            
            List<VprAudioInfo> prepareAudioInfos = new ArrayList<VprAudioInfo>();
            if(prepareAudioInfoMap != null && prepareAudioInfoMap.size()>0) {
            	
            	Path path = Paths.get(audioInfo.getWorkDir()+"/prepare");
                if (path.toFile().exists()) {
                    FileUtils.delete(path, true);
                }
                Files.createDirectories(path);
                
            	for(String key:prepareAudioInfoMap.keySet() ) {
            		PrepareAudioInfo prepareAudioInfo = prepareAudioInfoMap.get(key);
                    Files.copy(new ByteArrayInputStream(prepareAudioInfo.getBuffer().array()), Paths.get(prepareAudioInfo.getAudioPath()));
                    prepareAudioInfo.getBuffer().clear();
                    
                    VprAudioInfo vprAudioInfo = new VprAudioInfo();
                    vprAudioInfo.setAudioPath(prepareAudioInfo.getAudioPath());
                    vprAudioInfo.setUid(prepareAudioInfo.getUid());
                    
                    prepareAudioInfos.add(vprAudioInfo);
            	}
            }
            taskDoc.setPrepareAudioInfos(prepareAudioInfos);
            
            log.info("====processAudio prepareAudioInfos。size:{}",prepareAudioInfos.size());
            
        }finally {
			if (null != audioInputStream) {
				try {
					audioInputStream.close();
				} catch (IOException e) {
					throw new AsrException(
		                    ErrorCode.ERR_AUDIO_PREPARE_FAILED.errid,
		                    e.getMessage()
		            );
				}
			}
		}
        
        progressManager.syncToMongo(taskDoc, Progress.AUDIOPREPARED);
        taskDoc.addMetric("audioprepared_t");
    }
}
